import { DataType, determineDataType } from "../determineDataType/index.mjs";

/**
 * @description 支持的数据类型
 * @type {Array<DataType>}
 */
const supportDataType = [
  DataType.Object,
  DataType.Array,
  DataType.String,
  DataType.Number,
  DataType.Boolean,
  DataType.Undefined,
  DataType.Null,
  DataType.BigInt,
  DataType.Date,
  DataType.Map,
];

/**
 * @description 深拷贝
 * @param {Object} obj
 * @returns {Object | null}
 */
export const deepClone = (obj) => {
  const dataType = determineDataType(obj);
  if (
    dataType !== DataType.Object &&
    dataType !== DataType.Array &&
    dataType !== DataType.Map
  ) {
    console.warn("It only supports Object,Array,Map.");
    return null;
  }

  /**
   * @description 克隆结果
   * @type {any}
   */
  let result;

  /**
   *
   * @param {any} value
   * @param {string | number} key
   * @param {any} newTarget
   */
  const cloneLogic = (value, key, newTarget) => {
    const newTargetDataType = determineDataType(newTarget);

    /**
     * @description 写值
     * @param {any} _key
     * @param {any} _value
     */
    const setNewTargetValue = (_key, _value) => {
      if (
        newTargetDataType === DataType.Object ||
        newTargetDataType === DataType.Array
      ) {
        newTarget[_key] = _value;
      } else if (newTargetDataType === DataType.Map) {
        newTarget.set(_key, _value);
      }
    };

    /**
     * @description 读值
     * @param {any} _key
     * @returns {any}
     */
    const getNewTargetValue = (_key) => {
      if (
        newTargetDataType === DataType.Object ||
        newTargetDataType === DataType.Array
      ) {
        return newTarget[_key];
      } else if (newTargetDataType === DataType.Map) {
        return newTarget.get(_key);
      }
    };

    const valueDataType = determineDataType(value);
    if (supportDataType.includes(valueDataType)) {
      if (valueDataType === DataType.Object) {
        if (value === obj) {
          setNewTargetValue(key, newTarget);
        } else {
          setNewTargetValue(key, {});
          deepCloneObject(value, getNewTargetValue(key));
        }
      } else if (valueDataType === DataType.Array) {
        setNewTargetValue(key, []);
        deepCloneArray(value, getNewTargetValue(key));
      } else if (valueDataType === DataType.Date) {
        setNewTargetValue(key, new Date(value));
      } else {
        setNewTargetValue(key, value);
      }
    } else {
      console.warn(
        `${key}'s DataType is ${valueDataType}. It only supports ${supportDataType.join(
          ","
        )}`
      );
    }
  };

  /**
   * @description 深拷贝对象
   * @param {Object} target
   * @param {Object} newObj
   */
  const deepCloneObject = (target, newObj) => {
    const keys = Object.keys(target);
    for (let index = 0; index < keys.length; index++) {
      const key = keys[index];
      cloneLogic(target[key], key, newObj);
    }
  };

  /**
   * @description 深拷贝数组
   * @param {Array} target
   * @param {Array} newArr
   */
  const deepCloneArray = (target, newArr) => {
    for (let index = 0; index < target.length; index++) {
      cloneLogic(target[index], index, newArr);
    }
  };

  /**
   * @description 深拷贝Map
   * @param {Map} target
   * @param {Map} newMap
   */
  const deepCloneMap = (target, newMap) => {
    for (const [key, value] of target) {
      cloneLogic(value, key, newMap);
    }
  };

  if (dataType === DataType.Object) {
    result = {};
    deepCloneObject(obj, result);
  } else if (dataType === DataType.Array) {
    result = [];
    deepCloneArray(obj, result);
  } else if (dataType === DataType.Map) {
    result = new Map();
    deepCloneMap(obj, result);
  }

  return result;
};
